package jn.example.apt.handler;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class GenerateSetterGetterClassVisitor extends ClassVisitor {
  private String className;

  public GenerateSetterGetterClassVisitor(ClassWriter writer) {
    super(Opcodes.ASM7, writer);
  }

  @Override
  public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
    className = name;
    super.visit(version, access, name, signature, superName, interfaces);
  }

  @Override
  public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
    // 添加私有字段的公共 getter 和 setter 方法
    MethodVisitor getterMethodVisitor = super.visitMethod(Opcodes.ACC_PUBLIC, "get" + capitalize(name), "()" + desc, null, null);
    getterMethodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    getterMethodVisitor.visitFieldInsn(Opcodes.GETFIELD, className, name, desc);
    getterMethodVisitor.visitInsn(Opcodes.ARETURN);
    getterMethodVisitor.visitMaxs(1, 1);
    getterMethodVisitor.visitEnd();

    MethodVisitor setterMethodVisitor = super.visitMethod(Opcodes.ACC_PUBLIC, "set" + capitalize(name), "(" + desc + ")V", null, null);
    setterMethodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    setterMethodVisitor.visitVarInsn(getStoreOpcode(desc), 1);
    setterMethodVisitor.visitFieldInsn(Opcodes.PUTFIELD, className, name, desc);
    setterMethodVisitor.visitInsn(Opcodes.RETURN);
    setterMethodVisitor.visitMaxs(2, 2);
    setterMethodVisitor.visitEnd();

    return super.visitField(access, name, desc, signature, value);
  }

  // 辅助方法：将第一个字母转换为大写
  private String capitalize(String name) {
    return name.substring(0, 1).toUpperCase() + name.substring(1);
  }

  // 辅助方法：根据字段类型返回相应的存储指令
  private int getStoreOpcode(String desc) {
    if (desc.equals("Z") || desc.equals("B") || desc.equals("C") || desc.equals("S") || desc.equals("I")) {
      return Opcodes.ISTORE;
    } else if (desc.equals("F")) {
      return Opcodes.FSTORE;
    } else if (desc.equals("J")) {
      return Opcodes.LSTORE;
    } else if (desc.equals("D")) {
      return Opcodes.DSTORE;
    } else {
      return Opcodes.ASTORE;
    }
  }
}
